home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 April: Mac OS SDK / Dev.CD Apr 98 SDK1.toast / Development Kits (Disc 1) / QuickDraw 3D / Samples / SampleCode / SimpleViewer++ / SimpleViewer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-14  |  28.4 KB  |  1,167 lines  |  [TEXT/MPCC]

  1. //--------------------------------------------------------------------------------------------
  2. // simple viewer application 
  3. // DEVELOPER SUPPORT May 95
  4. //
  5. // This is a simple viewer application, that illustrates a minimal, but
  6. // functionally complete viewer application.
  7. //
  8. // Nick Thompson, Developer Support, Apple Computer (DEVSUPPORT),
  9. // ©1995, Apple Computer Inc., All Rights Reserved
  10.  
  11. #include <AppleEvents.h>
  12. #include <menus.h>
  13. #include <PictUtil.h>
  14. #include <QDOffScreen.h>
  15. #include <Errors.h>
  16.  
  17. #include "QD3DViewer.h"
  18.  
  19. #include "QD3D.h"
  20. #include "QD3DRenderer.h"
  21. #include "QD3DView.h"
  22. //--------------------------------------------------------------------------------------------
  23. //
  24. const int    kWindowWidth = 220 ;
  25. const int    kWindowHeight = 150 ;
  26.  
  27. //--------------------------------------------------------------------------------------------
  28. //
  29. #define HiWrd(aLong)    (((aLong) >> 16) & 0xFFFF)
  30. #define LoWrd(aLong)    ((aLong) & 0xFFFF)
  31.  
  32.     
  33.  
  34. //--------------------------------------------------------------------------------------------
  35. // menu id's
  36. enum {
  37.     mApple = 128,
  38.     mFile,
  39.     mEdit,
  40.     mView
  41. } ;
  42.  
  43. //--------------------------------------------------------------------------------------------
  44. // command id's, Apple menu
  45. enum {
  46.     iAbout = 1
  47. } ;
  48.  
  49. //--------------------------------------------------------------------------------------------
  50. // command id's, File menu
  51. enum {
  52.     iNew = 1,
  53.     iOpen,
  54.     iUnused1,
  55.     iClose,
  56.     iSave,
  57.     iSaveAs,
  58.     iRevert,
  59.     iUnused2,
  60.     iQuit
  61. } ;
  62.  
  63. //--------------------------------------------------------------------------------------------
  64. // command id's, Edit menu
  65. enum {
  66.     iUndo = 1,
  67.     iUnused3,
  68.     iCut,
  69.     iCopy,
  70.     iPaste,
  71.     iClear
  72. } ;
  73.  
  74. //--------------------------------------------------------------------------------------------
  75. // command id's, Edit menu
  76. enum {
  77.     iWireframe = 1,
  78.     iInteractive
  79. } ;
  80.  
  81. //--------------------------------------------------------------------------------------------
  82. // static control variables
  83.  
  84. static Boolean gQuitFlag = false ;                // we ain't quittin yet
  85. static Point gStaggerPos = {50,50} ;            // start opening staggered windows at this point
  86. static AEAddressDesc    gSelfAddress;            // A self-addressed address descriptor record
  87. static ProcessSerialNumber    gSelfPSN;            // This application's psn
  88.  
  89. //--------------------------------------------------------------------------------------------
  90. // function prototypes
  91.  
  92. Boolean SupportsQuickDraw3D(void) ;
  93. Boolean     SupportsQuickDraw3DViewer(void) ;
  94. void         InitToolbox( void ) ;
  95. void        FailIfErr(OSErr something ) ;
  96. void         MainEventLoop( void ) ;
  97. void         HandleKeyPress( EventRecord *event ) ;
  98. Boolean        HandleEvent( EventRecord *theEvent ) ;
  99. void         HandleMenuCommand( long menuResult ) ;
  100. void         MyAdjustMenus( void ) ;
  101. OSErr        MyDisposeViewerWindow( WindowPtr theWindow ) ;
  102. CGrafPtr     MyCreateViewerWindow( void ) ;
  103.  
  104. //-- AppleEvent Related
  105.  
  106. Boolean SupportsAEVT(void) ;
  107. void RegisterMyEvents(void) ;
  108. pascal OSErr MyAEHandleOAPP( AppleEvent *theAppleEvent, AppleEvent *reply, long refCon) ;
  109. pascal OSErr MyAEHandleODOC(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon) ;
  110. pascal OSErr MyAEHandlePDOC(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon) ;
  111. pascal OSErr MyAEHandleQUIT(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon) ;
  112. void DoAppOpenCommand( void ) ;
  113. void MySendQuitApp( void ) ;
  114. void MySendOpenDoc(FSSpec *myFSSpec) ;
  115.  
  116. //--------------------------------------------------------------------------------------------
  117. // Constants
  118.  
  119. const RGBColor    kRGBBlack = { 0x0000, 0x0000, 0x0000 } ;
  120. const RGBColor    kRGBWhite = { 0xFFFF, 0xFFFF, 0xFFFF } ;
  121. const int         kMyAboutDialogID = 128 ;
  122. const int         kMyFatalDialogID = 129 ;
  123. const int        kQD3DAlertID = 27309 ;
  124. //--------------------------------------------------------------------------------------------
  125. // Types
  126. typedef struct _viewerData {
  127.     TQ3ViewerObject        theViewer ;
  128.     FSSpec                theFile ;
  129.     Boolean                isFileValid ;
  130. } ViewerData, *ViewerDataPtr, **ViewerDataHandle ;
  131.  
  132. //--------------------------------------------------------------------------------------------
  133. //
  134. //
  135.  
  136. main()
  137. {
  138.     MoreMasters(); MoreMasters() ; MoreMasters() ;
  139.     MaxApplZone() ;            // Maximise the heap - the viewer requires at least 32k
  140.     InitToolbox() ;
  141.  
  142.     // WE DON'T CHECK FOR 68K machine.
  143.     // Instead I use the NotPPC.rsrc resource file.  This is a file with a 68k CODE 0
  144.     // and CODE 1 resource that puts up a dialog that says "this app only runs on a power
  145.     // macintosh computer.
  146.     
  147.     if( SupportsAEVT() && SupportsQuickDraw3D() && SupportsQuickDraw3DViewer()  ) {
  148.     
  149.         // AppleEvent stuff:
  150.         // Set up the self-addressed descriptor record.
  151.          gSelfPSN.highLongOfPSN = 0;
  152.          gSelfPSN.lowLongOfPSN = kCurrentProcess;        //* Use this instead of GetCurrentProcess *//
  153.          FailIfErr(AECreateDesc(typeProcessSerialNumber,(Ptr)&gSelfPSN,sizeof(ProcessSerialNumber),&gSelfAddress));
  154.  
  155.         RegisterMyEvents() ;    // register the appleevents for this app
  156.  
  157.         MainEventLoop() ;        // Handle events 'til we die
  158.     } 
  159.     else {
  160.         Str255 theString ;
  161.         GetIndString(theString,kQD3DAlertID,3);
  162.         ParamText( theString, 0L,  0L,  0L ) ;
  163.         (void)Alert(kQD3DAlertID,nil);
  164.     }
  165. }
  166. //---------------------------------------------------------------------
  167.  
  168. Boolean SupportsQuickDraw3D(void) 
  169. {
  170.     OSErr err;
  171.     long response;
  172.         
  173.     err = Gestalt(gestaltQD3D,&response);
  174.     if (err!=noErr)
  175.         return false;
  176.         
  177.     return (response && (response << gestaltQD3DAvailable));
  178. }
  179.  
  180. //---------------------------------------------------------------------
  181.  
  182. Boolean SupportsQuickDraw3DViewer(void) 
  183. {
  184.     OSErr err;
  185.     long response;
  186.         
  187.     err = Gestalt( gestaltQD3DViewer,&response );
  188.     if (err!=noErr)
  189.         return false;
  190.         
  191.     return (response && ( response << gestaltQD3DViewerAvailable ));
  192. }
  193.  
  194. //--------------------------------------------------------------------------------------------
  195. //
  196. //
  197. void FailIfErr( OSErr something )
  198.     OSErr myErr ; 
  199.     if(( myErr = something) != noErr ) { 
  200.         ModalFilterUPP         theProc ;
  201.         DialogPtr            theDialog ; 
  202.         short                itemHit ;
  203.         Str255                theError ;
  204.         
  205.         NumToString(something,theError);
  206.     
  207.         theDialog = GetNewDialog ( kMyFatalDialogID, nil, (WindowPtr)-1 );
  208.         
  209.         // these two lil' snappers are system 7 only
  210.         // so if you use them, check before!!
  211.         // in this app we will only run on Power
  212.         // Macintosh, so we don't check
  213.         
  214.         GetStdFilterProc( &theProc ) ;
  215.         SetDialogDefaultItem(theDialog, ok) ;
  216.         
  217.         ParamText( theError, 0L, 0L, 0L ) ;
  218.         
  219.         // put the dialog up and loop 'til
  220.         // the user hits the OK button
  221.  
  222.         do {
  223.             ModalDialog ( theProc, &itemHit );
  224.         } while( itemHit != ok ) ;
  225.         
  226.         DisposDialog ( theDialog );
  227.         
  228.         ExitToShell() ; 
  229.     } 
  230.  
  231. //--------------------------------------------------------------------------------------------
  232. //
  233. //
  234.  
  235. void InitToolbox()
  236. {
  237.     Handle        menuBar = nil;
  238.  
  239.  
  240.     InitGraf((Ptr) &qd.thePort);
  241.     InitFonts();
  242.     InitWindows();
  243.     InitMenus();
  244.     TEInit();
  245.     InitDialogs((long)nil);
  246.     InitCursor();
  247.  
  248.     // initialize application globals
  249.     
  250.     gQuitFlag = false;
  251.     
  252.     
  253.     menuBar = GetNewMBar(128);                // Read menus into menu bar, MBAR res id is 128
  254.     
  255.     if ( menuBar == nil )
  256.          ExitToShell();                        // if we dont have it then quit - your app 
  257.                                              // needs a dialog here
  258.  
  259.     SetMenuBar(menuBar);                    // Install menus
  260.     DisposHandle(menuBar);
  261.     
  262.     AddResMenu(GetMHandle(mApple), 'DRVR');    // Add DA names to Apple menu, ID 128
  263.  
  264.     MyAdjustMenus() ;
  265.     DrawMenuBar();
  266. }
  267.  
  268.  
  269. //--------------------------------------------------------------------------------------------
  270. //
  271. //
  272. void MainEventLoop()
  273. {
  274.     EventRecord         event;
  275.     WindowPtr           theWindow;
  276.     Boolean                wasViewerEvent ;
  277.     GrafPtr             savedPort ;
  278.     Point                localPt ;
  279.     TQ3ViewerObject     theViewer ;
  280.     ViewerDataHandle    myData ;
  281.     Boolean                didAdjustCursor ;
  282.  
  283.     MyAdjustMenus() ;
  284.     while( !gQuitFlag )
  285.     {
  286.         if (WaitNextEvent( everyEvent, &event, 0, nil ))
  287.         {
  288.             
  289.             if((theWindow = FrontWindow()) != nil ) {
  290.             
  291.                 myData = (ViewerDataHandle)GetWRefCon(theWindow);
  292.                 theViewer = (**myData).theViewer;
  293.             }
  294.             
  295.             if( theViewer ) {
  296.                 GetPort( &savedPort ) ;
  297.                 SetPort( (GrafPtr)theWindow ) ;
  298.                 GetMouse(&localPt);
  299.                 if (!(didAdjustCursor = Q3ViewerAdjustCursor(theViewer, &localPt))) {
  300.                     InitCursor();
  301.                 }
  302.                 else {
  303.                     DebugStr("\pQ3ViewerAdjustCursor returned true") ;
  304.                 }
  305.                 wasViewerEvent = Q3ViewerEvent ( theViewer, &event );
  306.                 SetPort( savedPort ) ;
  307.             }
  308.             else
  309.                 wasViewerEvent = false ;
  310.             
  311.             // was it a viewer event????
  312.             if( !wasViewerEvent ) {
  313.                 HandleEvent( &event );
  314.             } 
  315.         }
  316.     }
  317. }
  318.  
  319. //----------------------------------------------------------------------------------
  320. //    HandleActivateWindow is called when an event is received that reports that
  321. //    a window is being either activated or deactivated.
  322.  
  323. void HandleActivateWindow(WindowPtr theWindow, short activate)
  324. {
  325.     if (theWindow) {
  326.         if (activate) {
  327.         
  328.             // do whatever else you'd like to do for a activate event
  329.             LoadScrap() ;
  330.  
  331.         } else {
  332.         
  333.             // do whatever you'd like to do for a deactivate event
  334.             UnloadScrap() ;
  335.         }
  336.     }
  337. }
  338.  
  339. //--------------------------------------------------------------------------------------------
  340. //
  341. //
  342. Boolean        HandleEvent( EventRecord *theEvent )
  343. {
  344.     short               thePart;
  345.     WindowPtr            theWindow ;
  346.     Rect                screenRect;
  347.     GrafPtr                oldPort ;
  348.     Point                aPoint = {100, 100};
  349.     TQ3ViewerObject     theViewer = nil ;
  350.     ViewerDataHandle    myData ;
  351.     
  352.     switch (theEvent->what) {
  353.         case mouseDown:
  354.         
  355.             thePart = FindWindow( theEvent->where, &theWindow );
  356.             
  357.             switch( thePart ) {
  358.                 case inMenuBar: 
  359.                     MyAdjustMenus() ;
  360.                     HandleMenuCommand(MenuSelect(theEvent->where));
  361.                     break;
  362.                 
  363.                 case inDrag:
  364.                     screenRect = (**GetGrayRgn()).rgnBBox;
  365.                     DragWindow( theWindow, theEvent->where, &screenRect );
  366.                     break ;
  367.             
  368.                 case inContent:
  369.                     if (theWindow != FrontWindow())
  370.                         SelectWindow( theWindow );
  371.                     break ;
  372.             
  373.                 case inGoAway:
  374.                     if (TrackGoAway( theWindow, theEvent->where )) {
  375.                         MyDisposeViewerWindow( theWindow ) ;
  376.                     }
  377.                     break ;
  378.                     
  379.                 default:
  380.                     break ;
  381.             }
  382.             break ;
  383.                     
  384.                 
  385.         case updateEvt:
  386.         
  387.             theWindow = (WindowPtr)theEvent->message;
  388.             myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  389.             theViewer = (**myData).theViewer ;
  390.             
  391.             GetPort(&oldPort ) ;    
  392.             SetPort( theWindow );
  393.             
  394.             BeginUpdate( theWindow );
  395.             Q3ViewerDraw( theViewer ) ;
  396.             EndUpdate( theWindow );
  397.             
  398.             SetPort( oldPort ) ;
  399.             
  400.             break ;
  401.             
  402.         case keyDown:
  403.         case autoKey:
  404.             HandleKeyPress(theEvent);
  405.             break;
  406.             
  407.         case diskEvt:
  408.             if ( HiWrd(theEvent->message) != noErr ) 
  409.                 (void) DIBadMount(aPoint, theEvent->message);
  410.             break;
  411.             
  412.         case osEvt:
  413.             break ;
  414.         case activateEvt:
  415.             if ((theWindow = (WindowPtr) theEvent->message) != nil) {
  416.                 HandleActivateWindow(theWindow, (theEvent->modifiers & activeFlag));
  417.             }
  418.  
  419.             break;
  420.  
  421.         case kHighLevelEvent:                        // Let the Apple Event Manager handle high level event.
  422.             AEProcessAppleEvent(theEvent);
  423.             break;
  424.  
  425.     }
  426.     return true ;
  427. }
  428.  
  429.  
  430. //--------------------------------------------------------------------------------------------
  431. //
  432. //
  433. void HandleKeyPress(EventRecord *event)
  434. {
  435.     char    key;
  436.  
  437.     key = event->message & charCodeMask;
  438.     
  439.     // just check to see if we want to quit...
  440.     
  441.     if ( event->modifiers & cmdKey ) {        /* Command key down? */
  442.         HandleMenuCommand(MenuKey(key));
  443.     } 
  444. }
  445.  
  446. //--------------------------------------------------------------------------------------------
  447. //
  448. //
  449.  
  450. void HandleAboutApp( void )
  451. {
  452.     ModalFilterUPP         theProc ;
  453.     DialogPtr            theDialog ; 
  454.     short                itemHit ;
  455.  
  456.     theDialog = GetNewDialog ( kMyAboutDialogID, nil, (WindowPtr)-1 );
  457.     
  458.     // these two lil' snappers are system 7 only
  459.     // so if you use them, check before!!
  460.     // in this app we will only run on Power
  461.     // Macintosh, so we don't check
  462.     
  463.     GetStdFilterProc( &theProc ) ;
  464.     SetDialogDefaultItem(theDialog, ok) ;
  465.     
  466.     // put the dialog up and loop 'til
  467.     // the user hits the OK button
  468.     
  469.     do {
  470.         ModalDialog ( theProc, &itemHit );
  471.     } while( itemHit != ok ) ;
  472.     
  473.     DisposDialog ( theDialog );
  474. }
  475.  
  476. //--------------------------------------------------------------------------------------------
  477. //
  478. //
  479. OSErr HandleOpenDoc(FSSpec *theFile)
  480. {
  481.     OSErr                err ;
  482.     short                theRef ;
  483.     ViewerDataHandle    myData ;
  484.     TQ3ViewerObject     theViewer ;
  485.     WindowPtr            theWindow ;
  486.  
  487.     // display the contents
  488.     theWindow = (WindowPtr)MyCreateViewerWindow() ;
  489.     
  490.     // open the file
  491.     err = FSpOpenDF( theFile, fsRdPerm, &theRef ) ;
  492.     if (err == noErr)
  493.     {
  494.         myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  495.         theViewer = (**myData).theViewer ;
  496.         (**myData).theFile = *theFile ;
  497.         (**myData).isFileValid = true ;
  498.         Q3ViewerUseFile(theViewer, theRef) ;
  499.         err = FSClose(theRef) ;
  500.     }
  501.     
  502.     // set the window title
  503.     SetWTitle( theWindow, theFile->name );
  504.     MyAdjustMenus() ;
  505.     return err ;
  506. }
  507.  
  508.  
  509. //--------------------------------------------------------------------------------------------
  510. //
  511. //
  512. void HandleMenuCommand(long menuResult)
  513. {
  514.     short                menuID;
  515.     short                menuItem;
  516.     Str255                daName;
  517.     
  518.  
  519.     short                numTypes = 2 ;
  520.     SFTypeList            myTypes = { '3DMF', 'TEXT' } ;
  521.     OSErr                err ;
  522.     short                theRef ;
  523.     
  524.     ViewerDataHandle    myData ;
  525.     TQ3ViewerObject     theViewer ;
  526.     WindowPtr            theWindow ;
  527.     GrafPtr                savedPort ;
  528.     
  529.     FSSpec                theFile ;
  530.         
  531.     StandardFileReply    theSFReply ;
  532.  
  533.     menuID = HiWrd(menuResult);
  534.     menuItem = LoWrd(menuResult);
  535.     
  536.     switch ( menuID ) {
  537.         //
  538.         //--------------------------------------------------------------------------    
  539.         //
  540.         case mApple:
  541.             switch ( menuItem ) {
  542.  
  543.                 case iAbout:
  544.                     HandleAboutApp() ;    
  545.                     break ;
  546.                                 
  547.                 default:
  548.                     GetItem(GetMHandle(mApple), menuItem, daName);
  549.                     (void) OpenDeskAcc(daName);
  550.                     break;
  551.             }
  552.             break;
  553.         //
  554.         //--------------------------------------------------------------------------    
  555.         //
  556.         case mFile:
  557.             switch ( menuItem ) {
  558.                 case iNew:
  559.                     // display the contents
  560.                     (void)MyCreateViewerWindow() ;
  561.                     break ;
  562.                 
  563.                 case iOpen:
  564.                     // Get the file name to open
  565.                     StandardGetFile( nil, numTypes, myTypes, &theSFReply ) ;
  566.                     
  567.                     // did the user cancel, if not open the file?
  568.                     if(theSFReply.sfGood)
  569.                         MySendOpenDoc(&theSFReply.sfFile) ;
  570.  
  571.                     break ;
  572.                     
  573.                     
  574.                 case iRevert:
  575.                 
  576.                     // we know this can't be called as long as there
  577.                     // is an app window open (MyAdjustMenus) so get the refcon
  578.                     // from the front window and get the FSSpec from that
  579.                     theWindow = FrontWindow() ;
  580.                     myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  581.                     theFile = (**myData).theFile ;
  582.                     
  583.                     // open the file and read it back into the viewer
  584.                     err = FSpOpenDF( &theFile, fsRdPerm, &theRef ) ;
  585.                     if (err == noErr)
  586.                     {
  587.                         theViewer = (**myData).theViewer ;
  588.                         Q3ViewerUseFile(theViewer, theRef) ;
  589.                         err = FSClose(theRef) ;
  590.                     }
  591.                     GetPort( &savedPort ) ;
  592.                     SetPort((GrafPtr)theWindow) ;
  593.                     InvalRect( &theWindow->portRect ) ;
  594.                     SetPort( savedPort ) ;
  595.                     break ;        
  596.                             
  597.                 case iSave:                
  598.                 
  599.                     // we know this can't be called as long as there
  600.                     // is an app window open (MyAdjustMenus) so get the refcon
  601.                     // from the front window and get the FSSpec from that
  602.                     theWindow = FrontWindow() ;
  603.                     myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  604.                     theFile = (**myData).theFile ;
  605.                     theViewer = (**myData).theViewer ;
  606.  
  607.                     // assumes the original file still exists
  608.                     err = FSpOpenDF(&theFile, fsWrPerm, &theRef);
  609.                     if (err == noErr)
  610.                     {
  611.                         Q3ViewerWriteFile(theViewer, theRef);
  612.                         err = FSClose(theRef);
  613.                     }
  614.                     break ;
  615.                 
  616.                 case iSaveAs:
  617.                     // we know this can't be called as long as there
  618.                     // is an app window open (MyAdjustMenus) so get the refcon
  619.                     // from the front window and get the FSSpec from that
  620.                     theWindow = FrontWindow() ;
  621.                     myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  622.                     theViewer = (**myData).theViewer ;
  623.  
  624.                     StandardPutFile("\pSave model as:", "\pUntitled", &theSFReply);
  625.                     if (theSFReply.sfGood)
  626.                     {
  627.                         err = FSpOpenDF(&theSFReply.sfFile, fsWrPerm, &theRef);
  628.                         if (err != noErr)
  629.                         {
  630.                             err = FSpCreate(&theSFReply.sfFile, '????', '3DMF', theSFReply.sfScript);
  631.                             if (err == noErr)
  632.                                 err = FSpOpenDF(&theSFReply.sfFile, fsCurPerm, &theRef);
  633.                         }
  634.                         if (err == noErr)
  635.                         {
  636.                             Q3ViewerWriteFile(theViewer, theRef);
  637.                             err = FSClose(theRef);
  638.                         }
  639.                         
  640.                         // set up our record of the file location,
  641.                         // update the structure
  642.                         theWindow = FrontWindow() ;
  643.                         myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  644.                         theViewer = (**myData).theViewer ;
  645.                         (**myData).theFile = theSFReply.sfFile ;
  646.                         (**myData).isFileValid = true ;
  647.                         
  648.                         // reset the window title
  649.                         SetWTitle( theWindow, theSFReply.sfFile.name );
  650.                     }
  651.                     break;                
  652.                 
  653.                 case iClose:
  654.                     MyDisposeViewerWindow ( FrontWindow() );
  655.                     break ;
  656.                     
  657.                 case iQuit:
  658.                     MySendQuitApp();
  659.                     break;
  660.             }
  661.             break;
  662.             
  663.             
  664.         //
  665.         //--------------------------------------------------------------------------    
  666.         //
  667.         case mEdit:
  668.             // display the contents
  669.             theWindow = FrontWindow() ;
  670.             myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  671.             theViewer = (**myData).theViewer ;
  672.             switch(menuItem)
  673.             {
  674.                 case iCut:
  675.                     Q3ViewerCut(theViewer);
  676.                     break;
  677.                 case iCopy:
  678.                     Q3ViewerCopy(theViewer);
  679.                     break;
  680.                 case iPaste:
  681.                     Q3ViewerPaste(theViewer);
  682.                     break;
  683.                 case iClear:
  684.                     Q3ViewerClear(theViewer);
  685.                     break;
  686.                 default:
  687.                     break;
  688.             }
  689.             break; 
  690.             
  691.         case mView:
  692.             
  693.             theWindow = FrontWindow() ;
  694.             
  695.             if( theWindow == nil )
  696.                 break ;
  697.                 
  698.             myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  699.             theViewer = (**myData).theViewer ;
  700.             switch(menuItem)
  701.             {
  702.                 case iWireframe:
  703.                     {
  704.                         // get the view from the viewer
  705.                         TQ3ViewObject             myView = Q3ViewerGetView( theViewer );
  706.                         TQ3Status                myStatus;
  707.                         TQ3RendererObject        myRenderer;
  708.     
  709.                         // set the renderer to wireframe
  710.                         myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeWireFrame);
  711.                         if ((myStatus != Q3View_SetRenderer(myView, myRenderer)) == kQ3Failure ) {
  712.                             
  713.                             // dispose of the view, this reduces
  714.                             // the reference count and the changes we
  715.                             // made to the viewer's defualt will remain.
  716.                             Q3Object_Dispose( myView ) ;
  717.                         }
  718.                         Q3Object_Dispose( myRenderer ) ;
  719.  
  720.                     }
  721.                     break;
  722.                     
  723.                 case iInteractive:
  724.                     {
  725.                         // get the view from the viewer
  726.                         TQ3ViewObject             myView = Q3ViewerGetView( theViewer );
  727.                         TQ3Status                myStatus;
  728.                         TQ3RendererObject        myRenderer;
  729.     
  730.                         // set the renderer to use the interactive renderer
  731.                         myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeInteractive);
  732.                         if ((myStatus != Q3View_SetRenderer(myView, myRenderer)) == kQ3Failure ) {
  733.                             Q3Object_Dispose( myView ) ;
  734.                         }
  735.                         Q3Object_Dispose( myRenderer ) ;
  736.  
  737.                     }
  738.                     break;
  739.                     
  740.                 default:
  741.                     break;
  742.             }
  743.             GetPort( & savedPort ) ;
  744.             SetPort( theWindow ) ;
  745.             InvalRect( &theWindow->portRect ) ;
  746.             SetPort( savedPort ) ;
  747.             break;
  748.  
  749.     }
  750.     HiliteMenu(0);        // Unhighlight whatever MenuSelect or MenuKey hilited
  751. }
  752.  
  753. //--------------------------------------------------------------------------------------------
  754. //
  755. //
  756. void MyAdjustMenus( void ) 
  757. {
  758.     WindowPtr            theWindow ;
  759.     ViewerDataHandle    myData ;
  760.     MenuHandle            theMenu ;
  761.  
  762.     theWindow = FrontWindow() ;
  763.     
  764.     
  765.     if( theWindow != nil ) {
  766.     
  767.         theMenu =  GetMHandle ( mFile ) ;
  768.         
  769.         EnableItem ( theMenu, iClose );
  770.         EnableItem ( theMenu, iSaveAs );
  771.                  
  772.         myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  773.         
  774.          if(    (**myData).isFileValid) {
  775.             EnableItem ( theMenu, iSave );
  776.             EnableItem (theMenu, iRevert );
  777.          }
  778.          else {
  779.             DisableItem ( theMenu, iSave );
  780.             DisableItem ( theMenu, iRevert );
  781.          
  782.          }
  783.          
  784.          EnableItem ( GetMHandle ( mEdit ), 0 );
  785.  
  786.     }
  787.     else {
  788.  
  789.         theMenu =  GetMHandle ( mFile ) ;
  790.  
  791.         DisableItem ( theMenu, iClose );
  792.         DisableItem ( theMenu, iRevert );
  793.         DisableItem ( theMenu, iSave );
  794.         DisableItem ( theMenu, iSaveAs );
  795.         
  796.         DisableItem ( GetMHandle ( mEdit ), 0 );
  797.     }
  798.     
  799.     // we don't support undo
  800.     DisableItem ( GetMHandle ( mEdit ), iUndo );
  801.     
  802.     DrawMenuBar() ;
  803. }
  804.  
  805.  
  806. //--------------------------------------------------------------------------------------------
  807. //
  808. //
  809. OSErr    MyDisposeViewerWindow( WindowPtr theWindow )
  810. {
  811.     TQ3ViewerObject     theViewer ;
  812.     ViewerDataHandle    myData ;
  813.     
  814.     if( theWindow == nil)
  815.         return paramErr ;
  816.  
  817.     myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  818.     theViewer = (**myData).theViewer ;
  819.     
  820.     DisposHandle((Handle)myData);
  821.     DisposeWindow(theWindow);
  822.     
  823.     MyAdjustMenus() ;
  824.     return     Q3ViewerDispose(theViewer);
  825. }
  826.  
  827.  
  828. //--------------------------------------------------------------------------------------------
  829. //
  830. //
  831. CGrafPtr MyCreateViewerWindow(  )
  832. {
  833.  
  834.     Rect                theRect ;
  835.     GrafPtr                savedPort ;
  836.     TQ3ViewerObject        myViewerObj ;
  837.     WindowPtr            theWindow ;
  838.     ViewerDataHandle    myData = (ViewerDataHandle)NewHandle(sizeof(ViewerData)) ;
  839.     
  840.     GetPort( &savedPort ) ;
  841.         
  842.     // set the new rect up with a stagger for multiple windows
  843.     SetRect(    &theRect, 
  844.                 gStaggerPos.h, 
  845.                 gStaggerPos.v, 
  846.                 gStaggerPos.h + kWindowWidth, 
  847.                 gStaggerPos.v + kWindowHeight );
  848.  
  849.     gStaggerPos.h += 16 ;
  850.     gStaggerPos.v += 16 ;        // this is not "real staggering code, it don't wrap ;        
  851.                          
  852.     theWindow  = NewCWindow(    nil, 
  853.                                 &theRect, 
  854.                                 "\pUntitled", 
  855.                                 false, 
  856.                                 documentProc, 
  857.                                 (WindowPtr)-1, 
  858.                                 true, 
  859.                                 0L );    
  860.                     
  861.     SetPort( (GrafPtr)theWindow ) ;
  862.     
  863.     // set up the viewer object here
  864.     myViewerObj = Q3ViewerNew ((CGrafPtr)theWindow,  &theWindow->portRect,  kQ3ViewerDefault) ; 
  865.     
  866.     //stuff the reference to the viewer in the RefCon field of the Window
  867.     (**myData).theViewer = myViewerObj ;
  868.     (**myData).isFileValid = false ;
  869.     SetWRefCon( theWindow, (long)myData );
  870.     
  871.     // make sure it is visible
  872.     ShowWindow( theWindow ) ;
  873.     
  874.     // invalidate the content region of the window - 
  875.     // we don't do any drawing to it here.
  876.     InvalRect ( &theRect );
  877.     SetPort( savedPort ) ;
  878.     
  879.     return (CGrafPtr)theWindow ;
  880. }
  881.  
  882.  
  883. //-----------------------------------------------------------------------
  884. // returns true if the platform supports appleevents - we won't run
  885. // if it doesn't
  886.  
  887. Boolean SupportsAEVT(void)
  888. {
  889.     OSErr err;
  890.     long response;
  891.         
  892.     err = Gestalt(gestaltAppleEventsAttr,&response);
  893.     if (err!=noErr)
  894.         return false;
  895.         
  896.     return (response && (response << gestaltAppleEventsPresent));
  897. }
  898.  
  899. //-----------------------------------------------------------------------
  900. // called to register our appleevent handlers
  901.  
  902. void RegisterMyEvents(void)
  903. {
  904.     OSErr err;
  905.     
  906.     if (!SupportsAEVT())
  907.         return;
  908.     
  909.     err = AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,NewAEEventHandlerProc(MyAEHandleOAPP),0L,false);
  910.     if (err!=noErr)
  911.         return;
  912.                 
  913.     err = AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,NewAEEventHandlerProc(MyAEHandleODOC),0L,false);
  914.     if (err!=noErr)
  915.         return;
  916.                 
  917.     err = AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,NewAEEventHandlerProc(MyAEHandlePDOC),0L,false);
  918.     if (err!=noErr)
  919.         return;
  920.                 
  921.     err = AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,NewAEEventHandlerProc(MyAEHandleQUIT),0L,false);
  922.     if (err!=noErr)
  923.         return;
  924. }
  925.  
  926. //-----------------------------------------------------------------------
  927. // open application event handler for the core event suite, 
  928. // by default we just want a blank new document
  929.  
  930. pascal OSErr MyAEHandleOAPP( AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
  931. {
  932.     // we don't actually do anything on open - you could,
  933.     // for example you might want to open a blank untitled 
  934.     // window
  935.     
  936.     OSErr err = noErr ;
  937.     return err;
  938. }
  939.  
  940.  
  941. //-----------------------------------------------------------------------
  942. // handler for the open document appleevent handler
  943.  
  944. pascal OSErr MyAEHandleODOC(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
  945. {
  946.     FSSpec         myFSS;
  947.     AEDescList    docList;
  948.     OSErr        err,
  949.                 ignoreErr;
  950.     long        index,
  951.                 itemsInList;
  952.     Size         actualSize;
  953.     AEKeyword    keywd;
  954.     DescType    returnedType;
  955.  
  956.     
  957.     err = AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&docList);
  958.     if (err == noErr) {
  959.     
  960.         // see how many descriptor items are in the list
  961.         // this is the number of documents we want to open
  962.         err = AECountItems(&docList,&itemsInList);
  963.  
  964.         // now get each descriptor record from the list
  965.         // coerce the returned data to an FSSpec record, and
  966.         // open the asoociated file
  967.         
  968.         for (index=1; index <= itemsInList && err == noErr; index++) {
  969.         
  970.             err = AEGetNthPtr(    &docList, 
  971.                                 index,
  972.                                 typeFSS,
  973.                                 &keywd,
  974.                                 &returnedType,
  975.                                 (Ptr)&myFSS,
  976.                                 sizeof(myFSS),
  977.                                 &actualSize);
  978.     
  979.             if (err == noErr)    {
  980.             
  981.                 FInfo        fndrInfo ;
  982.                 
  983.                 // we now have a valid FSSpec to reference the file, we need to know 
  984.                 // what type the file is to determine which file open function to call
  985.                 // we can determine this from the finder info for the file
  986.                 
  987.                 err = FSpGetFInfo( &myFSS, &fndrInfo );    
  988.                 
  989.                 // if we got that ok, then we switch on the file  
  990.                 // type (we don't care about the creator type)    
  991.                         
  992.                 if (err == noErr)    {
  993.                 
  994.                     switch( fndrInfo.fdType ) {
  995.                         case 'TEXT':
  996.                         case '3DMF':
  997.                             err =  HandleOpenDoc(&myFSS);
  998.                             break ;
  999.                     }
  1000.                 }
  1001.             }
  1002.         }
  1003.         ignoreErr = AEDisposeDesc(&docList);
  1004.     }
  1005.     return err ;
  1006. }
  1007.  
  1008. //-----------------------------------------------------------------------
  1009. // handler for the print document event handler
  1010.  
  1011. pascal OSErr MyAEHandlePDOC(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon)
  1012. {
  1013.     FSSpec         myFSS;
  1014.     AEDescList    docList;
  1015.     OSErr        err;
  1016.     long        index,
  1017.                 itemsInList;
  1018.     Size         actualSize;
  1019.     AEKeyword    keywd;
  1020.     DescType    returnedType;
  1021.  
  1022.     
  1023.     err = AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&docList);
  1024.     if (err == noErr) {
  1025.     
  1026.         // see how many descriptor items are in the list
  1027.         // this is the number of documents we want to open
  1028.         err = AECountItems(&docList,&itemsInList);
  1029.  
  1030.         // now get each descriptor record from the list
  1031.         // coerce the returned data to an FSSpec record, and
  1032.         // open the asoociated file
  1033.         
  1034.         for (index=1; index <= itemsInList && err == noErr; index++) {
  1035.         
  1036.             err = AEGetNthPtr(    &docList, 
  1037.                                 index,
  1038.                                 typeFSS,
  1039.                                 &keywd,
  1040.                                 &returnedType,
  1041.                                 (Ptr)&myFSS,
  1042.                                 sizeof(myFSS),
  1043.                                 &actualSize);
  1044.     
  1045.             if (err == noErr)    {                    
  1046.                 // err = HandlePrintDoc( &myFSS );
  1047.                 err = errAEEventNotHandled ;         // we don't do this yet...
  1048.             }
  1049.         }
  1050.         err = AEDisposeDesc(&docList);
  1051.     }
  1052.     return err ;
  1053. }
  1054.  
  1055. //-----------------------------------------------------------------------
  1056. // quit appleevent handler
  1057.  
  1058. pascal OSErr MyAEHandleQUIT(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon)
  1059. {
  1060.     OSErr             err = noErr ;        // used as return value
  1061.     WindowPtr        theWindow ;
  1062.     Boolean            quitting = true ;
  1063.  
  1064.     
  1065.     // close all windows and signal to Quit
  1066.  
  1067.         
  1068.     // attempt to close all documents
  1069.     while(( theWindow = FrontWindow()) != nil && quitting )
  1070.         quitting = (MyDisposeViewerWindow( theWindow ) == noErr);    
  1071.         
  1072.  
  1073.     // if we closed everything up successfully, we can return noErr, otherwise
  1074.     // indicate to sender of the 'quit' aevt that we canceled
  1075.     
  1076.     if (quitting) {
  1077.         gQuitFlag = true;                    // user didn't cancel
  1078.          AEDisposeDesc(&gSelfAddress);        // Dispose of my self-addressed descriptor.
  1079.     }
  1080.     else {
  1081.         err = userCanceledErr ;
  1082.     }
  1083.             
  1084.     return err ;
  1085. }
  1086.  
  1087.  
  1088. //----------------------------------------------------------------------------------//
  1089. //    Send a Quit Application Apple Event to myself to terminate this app.        
  1090.  
  1091. void MySendQuitApp( void )
  1092. {
  1093.     AppleEvent    myAppleEvent, reply;
  1094.     
  1095.     //    Create the Apple Event.
  1096.     FailIfErr(AECreateAppleEvent( kCoreEventClass, 
  1097.                                   kAEQuitApplication, 
  1098.                                   &gSelfAddress,
  1099.                                   kAutoGenerateReturnID, 
  1100.                                   kAnyTransactionID, 
  1101.                                   &myAppleEvent));
  1102.                                   
  1103.     //    Send the Apple Event.
  1104.       FailIfErr(AESend( &myAppleEvent, 
  1105.                         &reply, 
  1106.                         kAENoReply+kAENeverInteract, 
  1107.                         kAENormalPriority,
  1108.                         kAEDefaultTimeout, 
  1109.                         nil, 
  1110.                         nil));
  1111.                         
  1112.       AEDisposeDesc(&myAppleEvent);                // Dispose of the Apple Event.
  1113. } // MySendQuitApp
  1114.  
  1115.  
  1116. //----------------------------------------------------------------------------------//
  1117. //    Send a Open Document Application Apple Event to myself to open a document.        
  1118.  
  1119. void MySendOpenDoc(FSSpec *myFSSpec)
  1120. {
  1121.      AppleEvent    myAppleEvent;
  1122.     AppleEvent    defReply;
  1123.     AEDescList    docList;
  1124.     OSErr         myErr;
  1125.     OSErr         ignoreErr;
  1126.     
  1127.     myAppleEvent.dataHandle = nil;
  1128.     docList.dataHandle  = nil;
  1129.     defReply.dataHandle = nil;
  1130.         
  1131.     // Create empty list and add one file spec
  1132.     FailIfErr(AECreateList(nil,0,false, &docList));
  1133.     
  1134.     FailIfErr(AEPutPtr(&docList,1,typeFSS,(Ptr)myFSSpec,sizeof(FSSpec)));
  1135.         
  1136.     FailIfErr(AECreateAppleEvent(    kCoreEventClass,
  1137.                                     kAEOpenDocuments,
  1138.                                     &gSelfAddress,
  1139.                                     kAutoGenerateReturnID,
  1140.                                     kAnyTransactionID,
  1141.                                     &myAppleEvent));
  1142.  
  1143.     // Put Params into our event and send it
  1144.  
  1145.     FailIfErr(AEPutParamDesc( &myAppleEvent,
  1146.                               keyDirectObject,
  1147.                               &docList));
  1148.  
  1149.     FailIfErr(AESend( &myAppleEvent,
  1150.                       &defReply,
  1151.                       kAENoReply+kAENeverInteract,
  1152.                       kAENormalPriority,
  1153.                       kAEDefaultTimeout,
  1154.                       nil,
  1155.                       nil));
  1156.         
  1157.         
  1158.     if (myAppleEvent.dataHandle) 
  1159.         ignoreErr = AEDisposeDesc(&myAppleEvent);
  1160.         
  1161.     if (docList.dataHandle) 
  1162.         ignoreErr = AEDisposeDesc(&docList);
  1163.             
  1164. }    // MySendOpenDoc 
  1165.